package edu.wpi.cs509.ui.images;

import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.HashMap;

import javax.imageio.ImageIO;

import edu.wpi.cs509.representation.StrategoPiece;
import edu.wpi.cs509.representation.TeamColor;


/**
 * The StrategoPieceImage class handles the management of graphics images for Stratego 
 * pieces.  It provides static access to the base image for each piece, and it supports
 * a convenience method for scaling the graphics image for display.  Use of this class
 * by all UI containers will ensure the pieces have consistent size and representation
 * throughout the GUI.
 * 
 * @author afoltan
 *
 */
public class StrategoPieceImage {

	// the preferred image graphic size in pixels;  all piece images
	// will be initially scaled to this dimension
	private static final int DEFAULT_WIDTH = 40;
	private static final int DEFAULT_HEIGHT = 60;
	
	// the default aspect ratio
    private static double aspectRatio = (double)((double)DEFAULT_WIDTH / (double)DEFAULT_HEIGHT);

	// a map of stratego piece to image
	private static HashMap<StrategoPiece, StrategoPieceImage> map = 
			new HashMap<StrategoPiece, StrategoPieceImage>();

	// the StrategoPieceImage object for each unique piece
	public static final StrategoPieceImage MARSHALL = 
			new StrategoPieceImage( StrategoPiece.MARSHAL, 
					"/edu/wpi/cs509/ui/images/red/1.png",
					"/edu/wpi/cs509/ui/images/blue/1.png");
	
	public static final StrategoPieceImage GENERAL = 
			new StrategoPieceImage( StrategoPiece.GENERAL, 
					"/edu/wpi/cs509/ui/images/red/2.png",
					"/edu/wpi/cs509/ui/images/blue/2.png");
	
	public static final StrategoPieceImage COLONEL = 
			new StrategoPieceImage( StrategoPiece.COLONEL, 
					"/edu/wpi/cs509/ui/images/red/3.png",
					"/edu/wpi/cs509/ui/images/blue/3.png");
	
	public static final StrategoPieceImage MAJOR = 
			new StrategoPieceImage( StrategoPiece.MAJOR, 
					"/edu/wpi/cs509/ui/images/red/4.png",
					"/edu/wpi/cs509/ui/images/blue/4.png");
	
	public static final StrategoPieceImage CAPTAIN = 
			new StrategoPieceImage( StrategoPiece.CAPTAIN, 
					"/edu/wpi/cs509/ui/images/red/5.png",
					"/edu/wpi/cs509/ui/images/blue/5.png");
	
	public static final StrategoPieceImage LIEUTENANT = 
			new StrategoPieceImage( StrategoPiece.LIEUTENANT, 
					"/edu/wpi/cs509/ui/images/red/6.png",
					"/edu/wpi/cs509/ui/images/blue/6.png");
	
	public static final StrategoPieceImage SERGENT = 
			new StrategoPieceImage( StrategoPiece.SERGEANT, 
					"/edu/wpi/cs509/ui/images/red/7.png",
					"/edu/wpi/cs509/ui/images/blue/7.png");
	
	public static final StrategoPieceImage MINER = 
			new StrategoPieceImage( StrategoPiece.MINER, 
					"/edu/wpi/cs509/ui/images/red/8.png",
					"/edu/wpi/cs509/ui/images/blue/8.png");
	
	public static final StrategoPieceImage SCOUT = 
			new StrategoPieceImage( StrategoPiece.SCOUT, 
					"/edu/wpi/cs509/ui/images/red/9.png",
					"/edu/wpi/cs509/ui/images/blue/9.png");
	
	public static final StrategoPieceImage SPY = 
			new StrategoPieceImage( StrategoPiece.SPY, 
					"/edu/wpi/cs509/ui/images/red/spy.png",
					"/edu/wpi/cs509/ui/images/blue/spy.png");
	
	public static final StrategoPieceImage BOMB = 
			new StrategoPieceImage( StrategoPiece.BOMB, 
					"/edu/wpi/cs509/ui/images/red/bomb.png",
					"/edu/wpi/cs509/ui/images/blue/bomb.png");
	
	public static final StrategoPieceImage FLAG = 
			new StrategoPieceImage( StrategoPiece.FLAG, 
					"/edu/wpi/cs509/ui/images/red/flag.png",
					"/edu/wpi/cs509/ui/images/blue/flag.png");

	public static final StrategoPieceImage HIDDEN = 
			new StrategoPieceImage( StrategoPiece.HIDDEN, 
					"/edu/wpi/cs509/ui/images/red/red.png",
					"/edu/wpi/cs509/ui/images/blue/blue.png");

	// image variable names
	private BufferedImage redImage, blueImage;
    
    // this class cannot be instantiated externally
	private StrategoPieceImage() {
	}
	
	/**
	 * The constructor for the StrategoPieceImage
	 * @param piece -the StrategoPiece represented by this object
	 * @param redPath - the resource path to the RED image
	 * @param bluePath - the resource path to the BLUE image
	 */
	private StrategoPieceImage( StrategoPiece piece, String redPath, String bluePath ) {
		BufferedImage tempImage;
		try {
			
			// load and scale the RED piece image
			tempImage = ImageIO.read(getClass().getResourceAsStream(redPath));
			
			// hack for older JRE
			int type = tempImage.getType();
			if (type ==0) type = 5;
			
			redImage = new BufferedImage(DEFAULT_WIDTH, DEFAULT_HEIGHT, type);
	    	
	    	Graphics2D iGraph = redImage.createGraphics();  
	    	iGraph.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);  
	    	iGraph.drawImage(tempImage, 0, 0, DEFAULT_WIDTH, DEFAULT_HEIGHT, 0, 0, tempImage.getWidth(), tempImage.getHeight(), null);  
	    	iGraph.dispose();

	    	// load and scale the BLUE piece image
			tempImage = ImageIO.read(getClass().getResourceAsStream(bluePath));
			
			// hack for older JRE
			type = tempImage.getType();
			if (type ==0) type = 5;
			
			blueImage = new BufferedImage(DEFAULT_WIDTH, DEFAULT_HEIGHT, type);
	    	
	    	iGraph = blueImage.createGraphics();  
	    	iGraph.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);  
	    	iGraph.drawImage(tempImage, 0, 0, DEFAULT_WIDTH, DEFAULT_HEIGHT, 0, 0, tempImage.getWidth(), tempImage.getHeight(), null);  
	    	iGraph.dispose();
			
		} catch (IOException e) {
			System.err.println("Could not find image");
		}
		
		// save this StrategoPieceImage object in the map
		map.put( piece, this );
	}
	
	/**
	 * Retreives the StrategoPieceImage object (not the graphics image)
	 * for the specified piece.
	 * @param piece - the stratego piece
	 * @return
	 */
	public static StrategoPieceImage get( StrategoPiece piece ) {
		return map.get(piece);
	}
	
	/**
	 * Retrieves the default image for the specified piece
	 * @param playerColor - the request player color
	 * @return - the standard piece image in the requested color
	 */
	public BufferedImage getImage( TeamColor playerColor ) {
		BufferedImage image;
		
		// select the correct color image
		if (playerColor.isRed()) {
			image = redImage;
		} else {
			image = blueImage;
		}

		return image;
	}
	
	/**
	 * A helper function to return the selected piece image in the selected player
	 * color, in the requested dimension size.  This routine will scale the image
	 * to the requested size.
	 * 
	 * @note - this routine will maintain the aspect ratio of the original piece image
	 * 
	 * @param playerColor - the specified player color for the image
	 * @param dim - the new scaled image dimensions
	 * @return - the scaled image
	 */
	public BufferedImage getScaledImage( TeamColor playerColor, Dimension dim ) {
		BufferedImage image, scaledImg;
		
		// select the correct color image
		if (playerColor.isRed()) {
			image = redImage;
		} else {
			image = blueImage;
		}
		
		// figure out the limiting dimension...
		double dimAspectRatio = (double)((double)dim.width / (double)dim.height);
		
		Dimension tgtDim = new Dimension();
		if (dimAspectRatio < aspectRatio) {
			// width is the limiting dimension
			tgtDim.width = dim.width;
			tgtDim.height = (int)((double)dim.width / aspectRatio);
		} else {
			// height is the limiting dimension
			tgtDim.height = dim.height;
			tgtDim.width = (int)((double)dim.height * aspectRatio);
		}
		
		// scale the image using the 2D graphics engine
		scaledImg = new BufferedImage(tgtDim.width, tgtDim.height, image.getType());
    	
    	Graphics2D iGraph = scaledImg.createGraphics();  
    	iGraph.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);  
    	iGraph.drawImage(image, 0, 0, tgtDim.width, tgtDim.height, 0, 0, image.getWidth(), image.getHeight(), null);  
    	iGraph.dispose();
    	
		return scaledImg;
	}

	/**
	 * Retrieves the preferred image height
	 * @return
	 */
	public int getHeight() {
		return DEFAULT_HEIGHT;
	}

	/**
	 * Retrieves the preferred image width
	 * @return
	 */
	public int getWidth() {
		return DEFAULT_WIDTH;
	}
	
	public Dimension getSize() {
		return new Dimension( getWidth(), getHeight() );
	}
	
	/**
	 * Retrieves the default graphic image aspect ratio
	 * @return
	 */
	public double getAspectRatio() {
		return aspectRatio;
	}

}

